package com.ccsu.mymarket.interceptor;


import com.ccsu.mymarket.exception.MyException;
import com.ccsu.mymarket.jwt.JWTUtils;
import com.ccsu.mymarket.jwt.PassToken;
import com.ccsu.mymarket.jwt.UserLoginToken;
import com.ccsu.mymarket.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

public class MyLoginInterceptor  implements HandlerInterceptor {
    @Autowired
    UserService userService=null;

    /**
     * 调用时间：Controller方法处理之前
     * 执行顺序：链式Intercepter情况下，Intercepter按照声明的顺序一个接一个执行
     * 若返回false，则中断执行，注意：不会进入afterCompletion
     * 处理登录时的token验证
     * @param httpServletRequest
     * @param httpServletResponse
     * @param object
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
        // 如果不是映射到方法直接通过
        if (!(object instanceof HandlerMethod)) {
            return true;
        }

        String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
        HandlerMethod handlerMethod = (HandlerMethod) object;

        Method method = handlerMethod.getMethod();
        Class beanClass=handlerMethod.getBeanType();

        System.out.println("用户传入的token："+token);
        System.out.println("请求方法："+method);

//          在方法上进行检查

        //检查是否有passtoken注释，有则跳过认证
        if (method.isAnnotationPresent(PassToken.class)) {
            PassToken passToken = method.getAnnotation(PassToken.class);
            if (passToken.required()) {
                return true;
            }
        }

        //检查类上是否有passtoken注释，有则跳过认证
        if (beanClass.isAnnotationPresent(PassToken.class)) {
            PassToken passToken = (PassToken)beanClass.getAnnotation(PassToken.class);
            if (passToken.required()) {
                return true;
            }
        }

        //检查有没有需要用户权限的注解
        if (method.isAnnotationPresent(UserLoginToken.class)) {
            UserLoginToken userLoginToken = method.getAnnotation(UserLoginToken.class);
            if (userLoginToken.required()) {
                // 执行认证
                if (token == null) {
                    throw new MyException("无token，请重新登录");
                }
                // 获取 token 中的 user id
                Integer userId = JWTUtils.vaildToken(token);
                if (userId==null) {
                    throw new MyException("解密后的用户id为空");
                }
//                    验证该用户id 是否存在，状态是否审核通过
                boolean state=userService.checkAcount(userId);
                if (!state)
                    return false;
            }
        }

//            在类上进行检查

        if (beanClass.isAnnotationPresent(UserLoginToken.class)){
            UserLoginToken userLoginToken = (UserLoginToken) beanClass.getAnnotation(UserLoginToken.class);
            if (userLoginToken.required()) {
                // 执行认证
                if (token == null) {
                    throw new MyException("无token，请登录后操作!");
                }
                // 获取 token 中的 user id
                Integer userId = JWTUtils.vaildToken(token);
                if (userId==null)
                    return false;
//                    验证该用户id 是否存在，状态是否审核通过
                boolean state=userService.checkAcount(userId);
                if (!state)
                    return false;
            }

        }
        return true;
    }

    /**
     * 调用前提：preHandle返回true
     * 调用时间：Controller方法处理完之后，DispatcherServlet进行视图的渲染之前，也就是说在这个方法中你可以对ModelAndView进行操作
     * 执行顺序：链式Intercepter情况下，Intercepter按照声明的顺序倒着执行。
     * 备注：postHandle虽然post打头，但post、get方法都能处理
     *
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest httpServletRequest,
                           HttpServletResponse httpServletResponse,
                           Object o, ModelAndView modelAndView) throws Exception {

    }

    /**
     * 调用前提：preHandle返回true
     * 调用时间：DispatcherServlet进行视图的渲染之后
     * 整个请求处理完毕回调方法,该方法也是需要当前对应的Interceptor的preHandle()的返回值为true时才会执行，
     * 用于进行资源清理。整个请求处理完毕回调方法。
     * 如性能监控中我们可以在此记录结束时间并输出消耗时间，还可以进行一些资源清理，
     * 类似于try-catch-finally中的finally，但仅调用处理器执行链中
     *
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @param e
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest,
                                HttpServletResponse httpServletResponse,
                                Object o, Exception e) throws Exception {
    }
}
